'''
Created on Nov 23, 2010

@author: dexen
'''

import sys
import time
import traceback
from StringIO import StringIO
import multiprocessing as mp
from multiprocessing.queues import Queue

from dexen.system.common.base import BaseSlaveTask
from dexen.system.node.slave.comm import InUnit
from dexen.system.common.meta import JobMeta, TaskMeta
from dexen.system.common.transact import SlaveSendTransact, SlaveRecvTransact
 


class SlaveTaskExecutor(mp.Process):
    def __init__(self, job_meta, inq, outq):
        mp.Process.__init__(self)
        self.job_meta = job_meta
        self.in_q = inq
        self.out_q = outq
    
    def _setup(self):
        job_meta = self.job_meta
        assert isinstance(job_meta, JobMeta)
        job_meta.setup_env()
    
    def _execute(self, unit):
        assert isinstance(unit, InUnit)
        transact = unit.transact
        master_state = unit.master_state
        assert isinstance(transact, SlaveSendTransact)
        task_meta = transact.get_task_meta()
        assert isinstance(task_meta, TaskMeta)                 
        try:
            sys.stdout = StringIO()
            sys.stderr = StringIO()
            slave_task = task_meta.get_obj()
            assert isinstance(slave_task, BaseSlaveTask)
            s_time = time.time()
            out_transact = transact.create_slave_recv_transact()           
            assert isinstance(out_transact, SlaveRecvTransact)
            inds = slave_task.__execute__(master_state, transact.get_inds())                
            out_transact.set_exec_time(time.time() - s_time)
            out_transact.set_inds(inds)
            out_transact.task_succeeded()
        except:
            out_transact.set_inds([])
            traceback.print_tb(sys.exc_info()[2])
            out_transact.set_err_msg(sys.stderr.getvalue())
            out_transact.set_exec_time(time.time() - s_time)
            out_transact.task_failed()
        finally:
            out_transact.set_out_msg(sys.stdout.getvalue())
            sys.stderr = sys.__stderr__
            sys.stdout = sys.__stdout__
            #print "Inds type\n", type(out_transact.inds)
            return out_transact
    
    def run(self):
        in_q = self.in_q
        out_q= self.out_q
        assert isinstance(in_q, Queue)
        assert isinstance(out_q, Queue)
        self._setup()
        try:
            while True:
                unit = in_q.get()
                transact = self._execute(unit)
                out_q.put(transact)
        except KeyboardInterrupt:
            print "Keyboard interreupt in slave executor"
        except:
            print "Slave executor in exception"
            

            
    